package org.raymond.iworks.study.basic.structure.sparsearray;


import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

// 稀疏数组
public class SparseArray {
    public static void main(String[] args) {
        // 创建一个原始的二维数组,11*11
        int[][] chessArr1 = createChessArr();
        // 将二维数组转为稀疏数组
        // 1. 先遍历二维数组,得到非0的有效数据的个数
        int sum = sum(chessArr1);
        System.out.println("sum:"+sum);
        // 2. 创建对应的稀疏数组
        int[][] sparseArr = createSparseArr(sum);
        // 3. 遍历二维数组,将非0的有效值存放到sparseArr中
        toSparseArr(chessArr1, sparseArr);

        System.out.println("得到的稀疏数组:");
        System.out.println("no\trow\tcol\tval\t");
        for(int i=0;i<sparseArr.length; i++){
            System.out.printf("%d\t%d\t%d\t%d\t\n", i, sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
        }
        System.out.println();

        // 课后练习1:将稀疏数组写入文件map.data
        String filename = "tmp/map.data";
        writeData(sparseArr, filename);

        // 课后练习2:从map.data读入稀疏数组
        int[][] sparseArr2 =  readData(filename);
        System.out.println("得到文件中的稀疏数组:");
        for(int i=0;i<sparseArr2.length; i++){
            System.out.printf("%d\t%d\t%d\t\n", sparseArr2[i][0], sparseArr2[i][1], sparseArr[i][2]);
        }
        System.out.println();

        // 将稀疏数组恢复为原始的二维数组
        int[][] chessArr2 = recoverChessArr(sparseArr2);
        System.out.println("得到的原始二维数组2:");
        for(int[] row : chessArr2){
            for(int data : row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }



    // 0-没有棋子,1-黑子,2-白子
    private static int[][] createChessArr(){
        int chessArr[][] = new int[11][11];
        chessArr[1][2]=1;
        chessArr[2][3]=2;
        chessArr[2][4]=1;
        System.out.println("原始的二维数组:");
        for(int[] row : chessArr){
            for(int data : row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        return chessArr;
    }


    private static int sum(int[][] chessArr){
        int sum = 0;
        for(int i=0; i<11; i++){
            for(int j=0; j<11; j++){
                if(chessArr[i][j]!=0){
                    sum++;
                }
            }
        }
        return sum;
    }

    private static int[][] createSparseArr(int sum){
        int sparseArr[][] = new int[sum+1][3];
        // 给稀疏数组赋值
        // 第一行第一列:行数
        sparseArr[0][0]=11;
        // 第一行第二列:列数
        sparseArr[0][1]=11;
        // 第一行第三列:sum
        sparseArr[0][2]=sum;
        return sparseArr;
    }
    private static void toSparseArr(int[][] chessArr, int[][] sparseArr){
        // 用于记录第几个非0数值
        int count = 0;
        for(int i=0; i<11; i++){
            for(int j=0; j<11; j++){
                if(chessArr[i][j]!=0){
                    count++;
                    sparseArr[count][0]=i;
                    sparseArr[count][1]=j;
                    sparseArr[count][2]=chessArr[i][j];
                }
            }
        }
    }

    private static void writeData(int[][] sparseArr, String filename){
        // 将稀疏数组组织为字符串内容
        StringBuilder dataBuilder = new StringBuilder();
        for(int i=0;i<sparseArr.length; i++){
            dataBuilder.append(sparseArr[i][0]).append("\t")
                    .append(sparseArr[i][1]).append("\t")
                    .append(sparseArr[i][2]).append("\t")
                    .append("\n")
            ;
        }

        // 将字符串内容写入文件
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byteBuffer.put(dataBuilder.toString().getBytes(StandardCharsets.UTF_8));
        byteBuffer.flip();

        try(FileChannel c = FileChannel.open(Path.of(filename), StandardOpenOption.CREATE,StandardOpenOption.WRITE)){
            c.write(byteBuffer);
        }catch (Exception e){
            System.err.println("error:"+e.getMessage());
        }
    }
    private static int[][] readData(String filename){
        // 从文件读入稀疏数组字符串内容
        String sparseArrContent = null;
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        try(FileChannel c = FileChannel.open(Path.of(filename), StandardOpenOption.READ)){
            c.read(byteBuffer);
            byteBuffer.flip();
            sparseArrContent = new String(byteBuffer.array(), StandardCharsets.UTF_8).trim();
        }catch (Exception e){
            System.err.println("error:"+e.getMessage());
            return new int[0][0];
        }
        System.out.println("从文件中读出来:");
        System.out.println(sparseArrContent);
        String[] sparseRecord = sparseArrContent.split("\n");
        String[] sparseMeta = sparseRecord[0].split("\t");
        int row = Integer.parseInt(sparseMeta[0]);
        int col = Integer.parseInt(sparseMeta[1]);
        int sum = Integer.parseInt(sparseMeta[2]);
        int[][] chessArr = new int[sum+1][3];
        chessArr[0][0] = row;
        chessArr[0][1] = col;
        chessArr[0][2] = sum;
        for(int i=1; i<chessArr.length; i++){
            String[] sparseVals = sparseRecord[i].split("\t");
            chessArr[i][0] = Integer.parseInt(sparseVals[0]);
            chessArr[i][1] = Integer.parseInt(sparseVals[1]);
            chessArr[i][2] = Integer.parseInt(sparseVals[2]);
        }
        return chessArr;
    }

    private static int[][] recoverChessArr(int[][] sparseArr){
        // 1. 读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
        int[][] chessArr = new int[sparseArr[0][0]][sparseArr[0][1]];
        int size = sparseArr[0][2]+1;
        // 2. 读取稀疏数组后面的数据,并赋值给原始的二维数组
        // 从稀疏数组的第二行开始遍历
        for(int i=1; i<size; i++){
            chessArr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
        return chessArr;
    }
}
